home *** CD-ROM | disk | FTP | other *** search
/ Supercompiler 1997 / SUPERCOMPILER97.iso / Delphi 3.0 / DATA.Z / masks.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1997-01-29  |  5.5 KB  |  267 lines

  1. unit Masks;
  2.  
  3. interface
  4.  
  5. type
  6.   TMask = class
  7.   private
  8.     FMask: Pointer;
  9.     FSize: Integer;
  10.   public
  11.     constructor Create(const MaskValue: string);
  12.     destructor Destroy; override;
  13.     function Matches(const Filename: string): Boolean;
  14.   end;
  15.  
  16. function MatchesMask(const Filename, Mask: string): Boolean;
  17.  
  18. implementation
  19.  
  20. uses SysUtils;
  21.  
  22. const
  23.   MaxCards = 30;
  24.  
  25. type
  26.   PMaskSet = ^TMaskSet;
  27.   TMaskSet = set of Char;
  28.   TMaskStates = (msLiteral, msAny, msSet);
  29.   TMaskState = record
  30.     SkipTo: Boolean;
  31.     case State: TMaskStates of
  32.       msLiteral: (Literal: Char);
  33.       msAny: ();
  34.       msSet: (
  35.         Negate: Boolean;
  36.         CharSet: PMaskSet);
  37.   end;
  38.   PMaskStateArray = ^TMaskStateArray;
  39.   TMaskStateArray = array[0..128] of TMaskState;
  40.  
  41. function InitMaskStates(const Mask: string;
  42.   var MaskStates: array of TMaskState): Integer;
  43. var
  44.   I: Integer;
  45.   SkipTo: Boolean;
  46.   Literal: Char;
  47.   P: PChar;
  48.   Negate: Boolean;
  49.   CharSet: TMaskSet;
  50.   Cards: Integer;
  51.  
  52.   procedure InvalidMask;
  53.   begin
  54.     raise Exception.CreateFmt('''%s'' is an invalid mask at (%d)', [Mask,
  55.       P - PChar(Mask) + 1]);
  56.   end;
  57.  
  58.   procedure Reset;
  59.   begin
  60.     SkipTo := False;
  61.     Negate := False;
  62.     CharSet := [];
  63.   end;
  64.  
  65.   procedure WriteScan(MaskState: TMaskStates);
  66.   begin
  67.     if I <= High(MaskStates) then
  68.     begin
  69.       if SkipTo then
  70.       begin
  71.         Inc(Cards);
  72.         if Cards > MaxCards then InvalidMask;
  73.       end;
  74.       MaskStates[I].SkipTo := SkipTo;
  75.       MaskStates[I].State := MaskState;
  76.       case MaskState of
  77.         msLiteral: MaskStates[I].Literal := UpCase(Literal);
  78.         msSet:
  79.           begin
  80.             MaskStates[I].Negate := Negate;
  81.             New(MaskStates[I].CharSet);
  82.             MaskStates[I].CharSet^ := CharSet;
  83.           end;
  84.       end;
  85.     end;
  86.     Inc(I);
  87.     Reset;
  88.   end;
  89.  
  90.   procedure ScanSet;
  91.   var
  92.     LastChar: Char;
  93.     C: Char;
  94.   begin
  95.     Inc(P);
  96.     if P^ = '!' then
  97.     begin
  98.       Negate := True;
  99.       Inc(P);
  100.     end;
  101.     LastChar := #0;
  102.     while not (P^ in [#0, ']']) do
  103.     begin
  104.       case P^ of
  105.         '-':
  106.           if LastChar = #0 then InvalidMask
  107.           else
  108.           begin
  109.             Inc(P);
  110.             for C := LastChar to UpCase(P^) do Include(CharSet, C);
  111.           end;
  112.       else
  113.         LastChar := UpCase(P^);
  114.         Include(CharSet, LastChar);
  115.       end;
  116.       Inc(P);
  117.     end;
  118.     if (P^ <> ']') or (CharSet = []) then InvalidMask;
  119.     WriteScan(msSet);
  120.   end;
  121.  
  122. begin
  123.   P := PChar(Mask);
  124.   I := 0;
  125.   Cards := 0;
  126.   Reset;
  127.   while P^ <> #0 do
  128.   begin
  129.     case P^ of
  130.       '*': SkipTo := True;
  131.       '?': if not SkipTo then WriteScan(msAny);
  132.       '[':  ScanSet;
  133.     else
  134.       Literal := P^;
  135.       WriteScan(msLiteral);
  136.     end;
  137.     Inc(P);
  138.   end;
  139.   Literal := #0;
  140.   WriteScan(msLiteral);
  141.   Result := I;
  142. end;
  143.  
  144. function MatchesMaskStates(const Filename: string;
  145.   MaskStates: array of TMaskState): Boolean;
  146. type
  147.   TStackRec = record
  148.     sP: PChar;
  149.     sI: Integer;
  150.   end;
  151. var
  152.   T: Integer;
  153.   S: array[0..MaxCards - 1] of TStackRec;
  154.   I: Integer;
  155.   P: PChar;
  156.  
  157.   procedure Push(P: PChar; I: Integer);
  158.   begin
  159.     with S[T] do
  160.     begin
  161.       sP := P;
  162.       sI := I;
  163.     end;
  164.     Inc(T);
  165.   end;
  166.  
  167.   function Pop(var P: PChar; var I: Integer): Boolean;
  168.   begin
  169.     if T = 0 then
  170.       Result := False
  171.     else
  172.     begin
  173.       Dec(T);
  174.       with S[I] do
  175.       begin
  176.         P := sP;
  177.         I := sI;
  178.       end;
  179.       Result := True;
  180.     end;
  181.   end;
  182.  
  183.   function Matches(P: PChar; Start: Integer): Boolean;
  184.   var
  185.     I: Integer;
  186.   begin
  187.     Result := False;
  188.     for I := Start to High(MaskStates) do
  189.       with MaskStates[I] do
  190.       begin
  191.         if SkipTo then
  192.         begin
  193.           case State of
  194.             msLiteral:
  195.               while (P^ <> #0) and (UpperCase(P^) <> Literal) do Inc(P);
  196.             msSet:
  197.               while (P^ <> #0) and not (Negate xor (UpCase(P^) in CharSet^)) do Inc(P);
  198.           end;
  199.           if P^ <> #0 then Push(@P[1], I);
  200.         end;
  201.         case State of
  202.           msLiteral: if UpperCase(P^) <> Literal then Exit;
  203.           msSet: if not (Negate xor (UpCase(P^) in CharSet^)) then Exit;
  204.         end;
  205.         Inc(P);
  206.       end;
  207.     Result := True;
  208.   end;
  209.  
  210. begin
  211.   Result := True;
  212.   T := 0;
  213.   P := PChar(Filename);
  214.   I := Low(MaskStates);
  215.   repeat
  216.     if Matches(P, I) then Exit;
  217.   until not Pop(P, I);
  218.   Result := False;
  219. end;
  220.  
  221. procedure DoneMaskStates(var MaskStates: array of TMaskState);
  222. var
  223.   I: Integer;
  224. begin
  225.   for I := Low(MaskStates) to High(MaskStates) do
  226.     if MaskStates[I].State = msSet then Dispose(MaskStates[I].CharSet);
  227. end;
  228.  
  229. { TMask }
  230.  
  231. constructor TMask.Create(const MaskValue: string);
  232. var
  233.   A: array[0..0] of TMaskState;
  234. begin
  235.   FSize := InitMaskStates(MaskValue, A);
  236.   FMask := AllocMem(FSize * SizeOf(TMaskState));
  237.   InitMaskStates(MaskValue, Slice(PMaskStateArray(FMask)^, FSize));
  238. end;
  239.  
  240. destructor TMask.Destroy;
  241. begin
  242.   if FMask <> nil then
  243.   begin
  244.     DoneMaskStates(Slice(PMaskStateArray(FMask)^, FSize));
  245.     FreeMem(FMask, FSize * SizeOf(TMaskState));
  246.   end;
  247. end;
  248.  
  249. function TMask.Matches(const Filename: string): Boolean;
  250. begin
  251.   Result := MatchesMaskStates(Filename, Slice(PMaskStateArray(FMask)^, FSize));
  252. end;
  253.  
  254. function MatchesMask(const Filename, Mask: string): Boolean;
  255. var
  256.   CMask: TMask;
  257. begin
  258.   CMask := TMask.Create(Mask);
  259.   try
  260.     Result := CMask.Matches(Filename);
  261.   finally
  262.     CMask.Free;
  263.   end;
  264. end;
  265.  
  266. end.
  267.